﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using DotSpatial.Controls;
using DotSpatial.Topology;
using System.Drawing;
using System.Drawing.Drawing2D;

using Point = System.Drawing.Point;
using DotSpatial.Data;
using System.Windows.Forms;

namespace HAGISV2
{
    public class HClipPolyMapFunction:HMapFunction
    {
        #region private variables

        //private IFeatureSet _featureSet;
        private List<Coordinate> _coordinates;

        private Point _mousePosition;

        private IMapLineLayer _tempLayer;

        private List<List<Coordinate>> _parts;
        private bool _disposed;

        
        
        Coordinate _currentCoords = new Coordinate();
        //MFSHAPETYPE _mfShapeType = MFSHAPETYPE.LINE;

        
        FeatureType _featureType=FeatureType.Line;

        #endregion

        public HClipPolyMapFunction(IMap map)
            : base(map)
        {
            //foreach(Feature f in map.Layers.SelectedLayer.)

            Configure();
        }

        private void Configure()
        {
            YieldStyle = (YieldStyles.LeftButton | YieldStyles.RightButton);

            _parts = new List<List<Coordinate>>();
        }


        #region Methods

        /// <summary>
        /// Forces this function to begin collecting points for building a new shape.
        /// </summary>
        protected override void OnActivate()
        {
            if (_standBy == false) { _coordinates = new List<Coordinate>(); }
            if (_tempLayer != null)
            {
                Map.MapFrame.DrawingLayers.Remove(_tempLayer);
                Map.MapFrame.Invalidate();
                Map.Invalidate();
                _tempLayer = null;
            }
            _standBy = false;
            base.OnActivate();
        }

        /// <summary>
        /// Allows for new behavior during deactivation.
        /// </summary>
        protected override void OnDeactivate()
        {
            base.OnDeactivate();

            this._coordinates = new List<Coordinate>();

        }

        /// <summary>
        /// Handles drawing of editing features.
        /// </summary>
        /// <param name="e">The drawing args for the draw method.</param>
        protected override void OnDraw(MapDrawArgs e)
        {
            if (_standBy) { return; }
            if (_featureType == FeatureType.Point) { return; }

            // Draw any completed parts first so that they are behind my active drawing content.
            if (_parts != null)
            {
                GraphicsPath gp = new GraphicsPath();

                List<Point> partPoints = new List<Point>();
                foreach (List<Coordinate> part in _parts)
                {
                    partPoints.AddRange(part.Select(c => Map.ProjToPixel(c)));
                    if (_featureType == FeatureType.Line)
                    {
                        gp.AddLines(partPoints.ToArray());
                    }
                    if (_featureType == FeatureType.Polygon)
                    {
                        gp.AddPolygon(partPoints.ToArray());
                    }
                    partPoints.Clear();
                }
                e.Graphics.DrawPath(Pens.Blue, gp);
                if (_featureType == FeatureType.Polygon)
                {
                    Brush fill = new SolidBrush(Color.FromArgb(70, Color.LightCyan));
                    e.Graphics.FillPath(fill, gp);
                    fill.Dispose();
                }
            }

            Pen bluePen = new Pen(Color.Blue, 2F);
            Pen redPen = new Pen(Color.Red, 3F);
            Brush redBrush = new SolidBrush(Color.Red);
            List<Point> points = new List<Point>();
            e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
            if (_coordinates != null)
            {
                points.AddRange(_coordinates.Select(coord => Map.ProjToPixel(coord)));
                foreach (Point pt in points)
                {
                    e.Graphics.FillRectangle(redBrush, new Rectangle(pt.X - 2, pt.Y - 2, 4, 4));
                }
                if (points.Count > 1)
                {

                    e.Graphics.DrawLines(bluePen, points.ToArray());
                }
                if (points.Count > 0 && _standBy == false)
                {

                    e.Graphics.DrawLine(redPen, points[points.Count - 1], _mousePosition);
                }
            }
            bluePen.Dispose();
            redPen.Dispose();
            redBrush.Dispose();
            base.OnDraw(e);
        }

        /// <summary>
        /// This method occurs as the mouse moves.
        /// </summary>
        /// <param name="e">The GeoMouseArcs class describes the mouse condition along with geographic coordinates.</param>
        protected override void OnMouseMove(GeoMouseArgs e)
        {
            if (_standBy) { return; }


            //存储临时点坐标

            this._currentCoords.X = e.GeographicLocation.X;
            this._currentCoords.Y = e.GeographicLocation.Y;




            if (_coordinates != null && _coordinates.Count > 0)
            {
                List<Point> points = _coordinates.Select(coord => Map.ProjToPixel(coord)).ToList();
                Rectangle oldRect = Global.GetRectangle(_mousePosition, points[points.Count - 1]);
                Rectangle newRect = Global.GetRectangle(e.Location, points[points.Count - 1]);
                Rectangle invalid = Rectangle.Union(newRect, oldRect);
                invalid.Inflate(20, 20);
                Map.Invalidate(invalid);
            }
            _mousePosition = e.Location;
            base.OnMouseMove(e);
        }

        /// <summary>
        /// Handles the Mouse-Up situation.
        /// </summary>
        /// <param name="e">The GeoMouseArcs class describes the mouse condition along with geographic coordinates.</param>
        protected override void OnMouseUp(GeoMouseArgs e)
        {
            if (_standBy) { return; }


            if (e.Button == MouseButtons.Right)
            {
                this.FinishShape();
                Map.Invalidate();
            }
            else
            {
                if (_coordinates == null) { _coordinates = new List<Coordinate>(); }
                _coordinates.Add(e.GeographicLocation);
                if (_coordinates.Count > 1)
                {
                    Point p1 = Map.ProjToPixel(_coordinates[_coordinates.Count - 1]);
                    Point p2 = Map.ProjToPixel(_coordinates[_coordinates.Count - 2]);
                    Rectangle invalid = Global.GetRectangle(p1, p2);
                    invalid.Inflate(20, 20);
                    Map.Invalidate(invalid);
                }
            }

            base.OnMouseUp(e);
        }

        /// <summary>
        /// Delete the shape currently being edited.
        /// </summary>
        /// <param name="sender">The sender of the DeleteShape event.</param>
        /// <param name="e">An empty EventArgument.</param>
        public void DeleteShape(object sender, EventArgs e)
        {
            _coordinates = new List<Coordinate>();
            _parts = new List<List<Coordinate>>();
            Map.Invalidate();
        }

        /// <summary>
        /// Finish the shape.
        /// </summary>
        /// <param name="sender">The object sender.</param>
        /// <param name="e">An empty EventArgs class.</param>
        public void FinishShape()
        {
            if (_coordinates.Count >= 2)
            {
                DoCutPolygons();
                //map操作
                
            }
            else return;
            _coordinates = new List<Coordinate>();
            _parts = new List<List<Coordinate>>();
        }

        void DoCutPolygons()
        {
            if (InteractiveSystem.CurrentLayer as VectorLayer != null)
            {
                VectorLayer vectorLayer = (VectorLayer)InteractiveSystem.CurrentLayer;
                List<VectorShape> copy = new List<VectorShape>();
                copy.AddRange(vectorLayer.SelectedShapes);

                
                foreach (VectorShape vs in copy)
                {
                    PolyShape pls = vs as PolyShape;
                    if (pls != null)
                    {
                        Polygon[] twoplg=new Polygon[]{};
                        if (TopologyTool.GetTwoFinalPolygon((Polygon)pls.Geometry, new LineString(_coordinates), ref twoplg))
                        {
                            if (twoplg.Length == 2)
                            {
                                //this.InteractiveSystem.HGMSAskDeleteShape(new HGMSSelectMFEventArgs(vectorLayer.Id, vs.Id, null, false));

                                
                                PolyShape ps = TopologyTool.PolygonToFetureObject(twoplg[0], "");

                                
                                List<Coordinate> coords = new List<Coordinate>();
                                coords.AddRange((ps.Geometry as Polygon).ExteriorRing.Coordinates.CloneList());
                                coords.RemoveAt(coords.Count - 1);

                                List<Coordinate[]> holes = new List<Coordinate[]>();
                                foreach (List<Coordinate> item in ps.Holes)
                                {
                                    holes.Add(item.ToArray());
                                }

                                //this.InteractiveSystem.AskAddShape(vs.GroupName, coords.ToArray(), holes, MFSHAPETYPE.POLYGON);

                                ps = TopologyTool.PolygonToFetureObject(twoplg[1], "");

                                coords = new List<Coordinate>();
                                coords.AddRange((ps.Geometry as Polygon).ExteriorRing.Coordinates.CloneList());
                                coords.RemoveAt(coords.Count - 1);

                                holes = new List<Coordinate[]>();
                                foreach (List<Coordinate> item in ps.Holes)
                                {
                                    holes.Add(item.ToArray());
                                }

                                //this.InteractiveSystem.AskAddShape(vs.GroupName, coords.ToArray(), holes, MFSHAPETYPE.POLYGON);

                            }
                        }
                    }
                }

            }

        }
        

        /// <summary>
        /// Finish the part of the shape being edited.
        /// </summary>
        /// <param name="sender">The object sender.</param>
        /// <param name="e">An empty EventArgs class.</param>
        public void FinishPart()
        {
            _parts.Add(_coordinates);
            _coordinates = new List<Coordinate>();
            Map.Invalidate();
        }

        /// <summary>
        /// Occurs when this function is removed.
        /// </summary>
        protected override void OnUnload()
        {
            if (Enabled)
            {
                _coordinates = null;

            }
            if (_tempLayer != null)
            {
                Map.MapFrame.DrawingLayers.Remove(_tempLayer);
                Map.MapFrame.Invalidate();

                _tempLayer = null;
            }
            Map.Invalidate();
        }

        #endregion

        #region Properties



        ///// <summary>
        ///// 要添加的图形类型
        ///// </summary>
        //public MFSHAPETYPE MfShapeType
        //{
        //    get { return _mfShapeType; }
        //    set
        //    {
        //        _mfShapeType = value;

        //        switch (this._mfShapeType)
        //        {
        //            case MFSHAPETYPE.POINT:
        //                this._featureType = FeatureType.Point;
        //                break;
        //            case MFSHAPETYPE.LINE:
        //                this._featureType = FeatureType.Line;

        //                break;
        //            case MFSHAPETYPE.POLYLINE:

        //                this._featureType = FeatureType.Line;

        //                break;
        //            case MFSHAPETYPE.POLYGON:

        //                this._featureType = FeatureType.Polygon;

        //                break;
        //            default:
        //                break;
        //        }

        //    }
        //}



        #endregion

        private void CoordinateDialogFormClosing(object sender, FormClosingEventArgs e)
        {
            // This signals that we are done with editing, and should therefore close up shop
            Enabled = false;
        }

        /// <summary>
        /// Actually, this creates disposable items but doesn't own them.
        /// When the ribbon disposes it will remove the items.
        /// </summary>
        public void Dispose()
        {
            Dispose(true);

            // This exists to prevent FX Cop from complaining.
            GC.SuppressFinalize(this);
        }

                /// <summary>
        /// Finalizes an instance of the AddShapeFunction class.
        /// </summary>
        ~HClipPolyMapFunction()
        {
            Dispose(false);
        }

        /// <summary>
        /// Gets a value indicating whether the "dispose" method has been called.
        /// </summary>
        public bool IsDisposed
        {
            get { return _disposed; }
        }

        /// <summary>
        /// Disposes this handler, removing any buttons that it is responsible for adding.
        /// </summary>
        /// <param name="disposeManagedResources">Disposes of the resources.</param>
        protected virtual void Dispose(bool disposeManagedResources)
        {
            if (!_disposed)
            {
                // One option would be to leave the non-working tools,
                // but if this gets disposed we should clean up after
                // ourselves and remove any added controls.
                if (disposeManagedResources)
                {
                   
                    
                  
                  
                    _coordinates = null;
                  
                    _tempLayer = null;
                   
                   
                    _parts = null;
                }
                _disposed = true;
            }
        }

    }
}
